//
//  main.m
//  08-iOS9NewFeatures
//
//  Created by 曹曹 on 16/7/13.
//  Copyright © 2016年 曹曹. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Truck.h"
#import "Student.h"

int main(int argc, const char * argv[]) {
#pragma mark - Nullability
    Person *per = [[Person alloc] init];
    // nonnull
    // 修饰属性对应的getter和setter方法
    NSString *string = nil;
    per.name = nil/**< 可以识别空值 */;
    [per setName:string];/**< 识别不了空值 */
    per.name = @"张三";
    [per name];
    // nullable
    // 修饰属性对应的getter和setter方法
    // per setGender:<#(NSString * _Nullable)#>];
    // [per gender];
    per.gender = @"";
    // null_resetable
    // setter可为空, gette不可为空
    // per setFriends:<#(NSArray * _Nullable)#>
    // [per friends]; NSArray * _Nonnull
#pragma mark - 泛型
    // 带泛型的容器(规定了容器中所存储的数据类型)
#pragma mark - 带泛型的数组
    // 声明一个可变数组, 内部存放的都是NSString
    // 1.数组中添加其他类型会有警告
    // 2.数组取出来的类型不再是id类型, 会对应变成声明时的类型
    // 3.泛型会改变类的一些方法, 使与声明的类型相同
    NSMutableArray<NSString *> *array = [NSMutableArray arrayWithObjects:@"123", @[], nil];
    [array addObject:@[]];
    NSMutableArray *array1 = [NSMutableArray array];
    // array.firstObject.length
    [array addObject:@""];
    // array addObject:<#(nonnull NSString *)#>
    [array1 addObject:@[]];
    // NSInteger integer = [array objectAtIndex:0].length;
#pragma mark - 带泛型的字典
    // NSMutableDictionary<NSString *, NSString *> *diction = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"哈哈", @"name", nil];
    // [diction objectForKey:@"name"].length;
    // diction objectForKey:<#(nonnull NSString *)#>
#pragma mark - 自定义泛型
    Truck<Person *> *truckPer = [[Truck alloc] init];
    Student *stu = [[Student alloc] init];
    stu.studentNumber = @"0101";
    [truckPer addObject:per];
    [truckPer addObject:stu];/**< student继承于person, 所以可以放在truck里 */
    Truck<Student *> *truckStu = [[Truck alloc] init];
    [truckStu addObject:stu];
    [truckStu addObject:per];
#pragma mark - 协变性与逆变性
    Truck *truck = [[Truck alloc] init];
    Truck<NSArray *> *truck1 = nil;
    Truck<NSMutableArray *> *truck2 = nil;
    // 大类型(任意类型) 可以给有泛型的赋值
    // 也可以有泛型的给它赋值
    truck = truck1;
    truck = truck2;
    truck1 = truck;
    truck2 = truck;
    // __covariant 协变性 子类在给父类赋值时, 自动强转
    // Truck<NSArray *> 与 Truck<NSMutableArray *>
    truck1 = truck2;
    // 逆变性 __contracovariant 逆变性: 父类型可以强制转换成子类型
    truck2 = truck1;
#pragma mark - __kindof 一般用在方法的返回值
    // 加__kindof修饰后, 返回的类型及其子类型都可以接收这个返回值
    Truck *truck3 = [[Truck alloc] init];
    NSMutableArray *mArrayKindof = (NSMutableArray *)[truck3 returnArray];
    NSArray *arrayKindof = [truck3 returnArray];
    NSMutableArray *arr = [truck3 returnArray];
    return 0;
}
